#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import pygame
from bullet import Bullet
from alien import Alien
from time import sleep

"""
#每次用户按键时候,都会在 pygame 里面注册一个事件( event)
#事件都是通过 pygame.event.get()获取
#每个按键都被注册为一个 KEYDOWN 事件, 检测到 KEYDOWN事件时,检测按下了什么键,如果是右键,
#增加飞船的 rect.centerx 的值, 将飞船向右移动.
"""


def check_keydown_events(event, ai_settings, screen, ship, bullets):
    """响应按键按下时候的事件"""
    if event.key == pygame.K_RIGHT or event.key == pygame.K_d:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT or event.key == pygame.K_a:
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        fire_bullet(ai_settings, screen, ship, bullets)
    elif event.key == pygame.K_q or event.key == pygame.K_ESCAPE:
        sys.exit()


def fire_bullet(ai_settings, screen, ship, bullets):
    """定义个开火的函数,来简化 check_keydown_events函数,当按下空格的状态被检测到以后,
    应该创建一个子弹的实例,并将其加入到 bullets精灵组里面."""
    if len(bullets) < ai_settings.bullet_allowed:
        new_bullet = Bullet(ai_settings, screen, ship)
        bullets.add(new_bullet)


def check_keyup_events(event, ship):
    """响应按键松开事件的处理"""
    if event.key == pygame.K_RIGHT or event.key == pygame.K_d:
        ship.moving_right = False
    elif event.key == pygame.K_LEFT or event.key == pygame.K_a:
        ship.moving_left = False


def check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y):
    """在玩家单击 play 按钮时候开始新游戏"""
    if play_button.rect.collidepoint(mouse_x, mouse_y):
        stats.reset_stats()
        stats.game_active = True

        # 清空外星人和子弹
        aliens.empty()
        bullets.empty()

        # 创建新的一批外星人和将飞船居中
        create_fleet(ai_settings, screen, ship, aliens)
        ship.center_ship()


def check_events(ai_settings, screen, stats, play_button, ship, aliens, bullets):
    """响应系统按键和鼠标事件"""
    for event in pygame.event.get():  # 遍历捕获到的系统鼠标或者键盘事件
        if event.type == pygame.QUIT:
            sys.exit()
        # 检测按键按下,然后判断是否向右,如果向右,飞船移动标识就为 True.
        elif event.type == pygame.KEYDOWN:
            check_keydown_events(event, ai_settings, screen, ship, bullets)

        elif event.type == pygame.KEYUP:
            check_keyup_events(event, ship)

        elif event.type == pygame.MOUSEBUTTONDOWN:
            mouse_x, mouse_y = pygame.mouse.get_pos()
            check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y)


def update_screen(ai_settings, screen, stats, ship, aliens, bullets, play_button):
    """更新屏幕上的图像, 并切换到新屏幕"""
    # 每次循环的时候都重新绘制屏幕
    screen.fill(ai_settings.bg_color)
    # 绘制子弹,然后绘制飞船
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    # 绘制飞船
    ship.blitme()
    aliens.draw(screen)
    if not stats.game_active:
        play_button.draw_button()

    # 让最近绘制的屏幕可见
    pygame.display.flip()


def update_bullets(ai_settings, screen, ship, aliens, bullets):
    """更新子弹的位置,并删除已经消失的子弹"""
    bullets.update()  # 更新子弹位置
    check_bullet_alien_collisions(ai_settings, screen, ship, bullets, aliens)  # 检查是否产生了碰撞并执行相关的操作.
    # 检查子弹是否已经飞出了我们定义的屏幕,如果已经飞出,就删除子弹.
    for bullet in bullets.copy():
        """一般情况下, 在 for 循环里面,不应该从列表或者编组中直接删除条目,因此必须遍历编组的副本.使用 copy() 来设置 for 循环."""
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)


def check_bullet_alien_collisions(ai_settings, screen, ship, bullets, aliens):
    """响应子弹和外星人的碰撞"""
    # 删除精灵组中的精灵
    # 如果是击中了外星人,子弹和外星人都要从精灵组里删除.
    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
    if len(aliens) == 0:
        bullets.empty()
        # 判断精灵组里面是否还有外星人, aliens精灵组里面如果为空, 则需要调用 create_fleet() 创建一批外星人.
        # 先清空屏幕上遗留的子弹,然后再添加一批外星人.
        create_fleet(ai_settings, screen, ship, aliens)


def create_fleet(ai_settings, screen, ship, aliens):
    """创建外星人群"""
    alien = Alien(ai_settings, screen)
    number_aliens_x = get_number_alien_x(ai_settings, alien.rect.width)
    number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height)

    # 创建第一行外星人
    for row_number in range(number_rows):
        for alien_number in range(number_aliens_x):
            create_alien(ai_settings, screen, aliens, alien_number, row_number)


def get_number_alien_x(ai_settings, alien_width):
    """计算每行可以容纳的外星人数量"""
    available_space_x = ai_settings.screen_width - 2 * alien_width
    number_aliens_x = int(available_space_x / (2 * alien_width))
    return number_aliens_x


def get_number_rows(ai_settings, ship_height, alien_height):
    """计算屏幕剩余空间可以容纳多少行外星人"""
    available_space_y = (ai_settings.screen_height - (3 * alien_height) - ship_height)
    number_rows = int(available_space_y / (2 * alien_height))
    return number_rows


def create_alien(ai_settings, screen, aliens, alien_number, row_number):
    """创建一个外星人,并将它放在当前行里面"""
    alien = Alien(ai_settings, screen)
    # 定义外星人间距为外星人的宽度
    alien_width = alien.rect.width
    alien.x = alien_width + 2 * alien_width * alien_number
    alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
    alien.rect.x = alien.x
    aliens.add(alien)


def check_fleet_edges(ai_settings, aliens):
    """当有外星人到达边缘的时候才去响应的措施, 我们思路是到达边缘向相反的方向移动"""
    # 利用 for 循环遍历 aliens.sprites(),得到的是精灵组的成员-单个的精灵.
    for alien in aliens.sprites():
        if alien.check_edges():
            # 当检查到外星人碰到屏幕边缘的时候( check_edges() 函数返回值为真的时候)
            change_fleet_direction(ai_settings, aliens)
            break


def change_fleet_direction(ai_settings, aliens):
    """将整个群外星人向下移, 并改变他们的方向"""
    for alien in aliens.sprites():
        alien.rect.y += ai_settings.fleet_drop_speed
    # 利用乘法运算做反方向移动 ai_settings.fleet_direction = ai_settings.fleet_direction * (-1)
    ai_settings.fleet_direction *= -1


def ship_hit(ai_settings, stats, screen, ship, aliens, bullets):
    """响应被外星人撞到的飞船"""
    if stats.ships_left > 0:
        # 将飞船剩余数量减去1  ship_left - 1
        stats.ships_left -= 1

        # 清空外星人列表和子弹列表
        aliens.empty()
        bullets.empty()

        # 重新创建一批外星人, 并将飞船放置到屏幕的底端中央位置
        create_fleet(ai_settings, screen, ship, aliens)
        ship.center_ship()

        # 暂停点儿时间让用户反应过来
        sleep(0.5)
    else:
        stats.game_active = False


def check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets):
    """检查外星人是否到达屏幕低端"""
    # 获取屏幕外框
    screen_rect = screen.get_rect()
    for alien in aliens.sprites():
        if alien.rect.bottom >= screen_rect.bottom:
            ship_hit(ai_settings, stats, screen, ship, aliens, bullets)
            break


def update_aliens(ai_settings, stats, screen, ship, aliens, bullets):
    """检查是否有外星人位于屏幕的边缘, 并更新整群外星人的位置"""
    check_fleet_edges(ai_settings, aliens)
    aliens.update()
    # 检测外星人和飞船之间的碰撞
    if pygame.sprite.spritecollideany(ship, aliens):
        ship_hit(ai_settings, stats, screen, ship, aliens, bullets)

    check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets)
